using UnityEngine;
using MinesweeperPlus.Scripts.Abstractions.Interfaces;
using MinesweeperPlus.Scripts.Abstractions.Enums;
using MinesweeperPlus.Scripts.Configs;

namespace MinesweeperPlus.Scripts.Objects
{
    public class Cell : IGameObject
    {
        #region Constants
        private const string FLAG_NAME = "Flag";
        private const string HEAD_NAME = "Head";
        private const string BODY_NAME = "Body";
        private const string BACK_NAME = "Back";
        #endregion

        #region Variables
        private CellConfig _config;

        private GameObject _gameObject;

        private GameObject _flagGO;
        private SpriteRenderer _flagSR;

        private GameObject _headGO;
        private SpriteRenderer _headSR;

        private GameObject _bodyGO;
        private SpriteRenderer _bodySR;

        private GameObject _backGO;
        private SpriteRenderer _backSR;
        
        private CellBodyType _bodyType;
        #endregion
        #region Properties
        public CellBodyType BodyType 
        {
            get { return _bodyType; }
            set 
            {
                _bodyType = value;
                _bodySR.sprite = _config.BodySprites[(int)_bodyType];
            }
        }
        public bool IsActive 
        {
            get { return _gameObject.activeSelf; }
            set { _gameObject.SetActive(value); }
        }
        public Transform Transform { get; private set; }
        public bool IsFlagged { get; private set; }
        public bool IsOpened { get; private set; }
        #endregion

        #region Cell Methods
        public Cell(CellConfig config)
        {
            _config = config;
            _gameObject = GameObject.Instantiate(_config.Prefab);
            Transform = _gameObject.transform;
            IsFlagged = true;
            IsOpened = false;
            IsActive = true;

            _headGO = GetGameObject(Transform, HEAD_NAME);
            _headSR = GetSpriteRenderer(_headGO);
            
            _flagGO = GetGameObject(_headGO.transform, FLAG_NAME);
            _flagSR = GetSpriteRenderer(_flagGO);

            _bodyGO = GetGameObject(Transform, BODY_NAME);
            _bodySR = GetSpriteRenderer(_bodyGO);

            _backGO = GetGameObject(Transform, BACK_NAME);
            _backSR = GetSpriteRenderer(_backGO);

            RefreshCell();
            Reset();
        }

        public void Flag()
        {
            if (IsFlagged || IsOpened) 
                return;

            IsFlagged = true;
            _flagGO.SetActive(true);
        }
        public void Unflag()
        {
            if (!IsFlagged) 
                return;

            IsFlagged = false;
            _flagGO.SetActive(false);
        }

        public void Open()
        {
            if (IsOpened || IsFlagged) 
                return;

            IsOpened = true;
            _headGO.SetActive(false);
        }
        public void Close()
        {
            if (!IsOpened) 
                return;

            IsOpened = false;
            _headGO.SetActive(true);
        }
        
        public void NextBodyType() =>
            BodyType = (CellBodyType)(((int)_bodyType + 1) % _config.BodySprites.Length);
        
        public void Reset()
        {
            Close();
            Unflag();
            BodyType = CellBodyType.None;
        }
        
        public void Destroy()
        {
            GameObject.Destroy(_gameObject);
        }
        #endregion

        #region Other Methods
        private void RefreshCell()
        {
            _flagSR.sprite = _config.FlagSprite;
            _headSR.sprite = _config.HeadSprite;
            BodyType = _bodyType;
            _backSR.sprite = _config.BackSprite;
        }

        private GameObject GetGameObject(Transform parent, string goName) =>
            parent.Find(goName).gameObject;
        private SpriteRenderer GetSpriteRenderer(GameObject go) =>
            go.GetComponent<SpriteRenderer>();
        #endregion
    }
}
